package com.phiture.erp.produce.web.controller.admin;

import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.framework.common.core.KeyValue;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
import cn.iocoder.yudao.module.system.dal.dataobject.dict.DictDataDO;
import cn.iocoder.yudao.module.system.service.dict.DictDataService;
import com.phiture.erp.basic.api.pojo.resp.ErpMaterialInfoResp;
import com.phiture.erp.basic.api.pojo.resp.ErpMaterialResp;
import com.phiture.erp.basic.api.pojo.resp.ErpMaterialUnitResp;
import com.phiture.erp.basic.api.service.ErpMaterialApi;
import com.phiture.erp.basic.api.service.ErpMaterialUnitApi;
import com.phiture.erp.common.constants.DictTypeConstants;
import com.phiture.erp.common.enums.ErpMaterialAttrEnum;
import com.phiture.erp.produce.core.pojo.vo.ErpBomItemsRespVO;
import com.phiture.erp.produce.core.pojo.vo.ErpBomPageReqVO;
import com.phiture.erp.produce.core.pojo.vo.ErpBomRespVO;
import com.phiture.erp.produce.core.pojo.vo.ErpBomSaveReqVO;
import com.phiture.erp.produce.core.service.BomGroupStandardService;
import com.phiture.erp.produce.core.service.ErpBomService;
import com.phiture.erp.produce.core.service.ErpProduceProcessService;
import com.phiture.erp.produce.dal.entity.*;
import com.phiture.erp.produce.dal.pojo.dto.ErpBomDTO;
import com.phiture.erp.stock.api.service.ErpWarehouseApi;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.security.access.prepost.PreAuthorize;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Operation;

import javax.validation.*;
import javax.servlet.http.*;
import java.util.*;
import java.io.IOException;

import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;

import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;

import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;

@Tag(name = "管理后台 - bom")
@RestController
@RequestMapping("/erp/bom")
@Validated
public class ErpBomController {

    @Resource
    private ErpBomService bomService;

    @Resource
    private ErpMaterialApi erpMaterialApi;

    @Resource
    private DictDataService dictDataService;

    @Resource
    private ErpMaterialUnitApi erpMaterialUnitApi;

    @Resource
    private ErpWarehouseApi erpWarehouseApi;
    @Resource
    private BomGroupStandardService bomGroupStandardService;

    @Resource
    private ErpProduceProcessService erpProduceProcessService;

    @PostMapping("/create")
    @Operation(summary = "创建bom")
    @PreAuthorize("@ss.hasPermission('erp:bom:create')")
    public CommonResult<Long> createBom(@Valid @RequestBody ErpBomSaveReqVO createReqVO) {
        return success(bomService.createBom(createReqVO));
    }

    @PutMapping("/update")
    @Operation(summary = "更新bom")
    @PreAuthorize("@ss.hasPermission('erp:bom:update')")
    public CommonResult<Boolean> updateBom(@Valid @RequestBody ErpBomSaveReqVO updateReqVO) {
        bomService.updateBom(updateReqVO);
        return success(true);
    }

    @DeleteMapping("/delete")
    @Operation(summary = "删除bom")
    @Parameter(name = "id", description = "编号", required = true)
    @PreAuthorize("@ss.hasPermission('erp:bom:delete')")
    public CommonResult<Boolean> deleteBom(@RequestParam("id") Long id) {
        bomService.deleteBom(id);
        return success(true);
    }

    @GetMapping("/get")
    @Operation(summary = "获得bom")
    @Parameter(name = "id", description = "编号", required = true, example = "1024")
    @PreAuthorize("@ss.hasPermission('erp:bom:query')")
    public CommonResult<ErpBomRespVO> getBom(@RequestParam("id") Long id) {
        ErpBomDO bom = bomService.getBom(id);
        return success(BeanUtils.toBean(bom, ErpBomRespVO.class));
    }

    @GetMapping("/getUnBomMaterial")
    @Operation(summary = "获得未有bom的物料")
    public CommonResult<List<ErpMaterialResp>> getUnBomMaterial() {
        List<ErpMaterialResp> result = bomService.getUnBomMaterial();
        return success(result);
    }

    @GetMapping("/page")
    @Operation(summary = "获得bom分页")
    @PreAuthorize("@ss.hasPermission('erp:bom:query')")
    public CommonResult<PageResult<ErpBomDTO>> getBomPage(@Valid ErpBomPageReqVO pageReqVO) {
        PageResult<ErpBomDO> pageResult = bomService.getBomPage(pageReqVO);
        return success(buildErpBomRespVoPageResult(pageResult));
//        return success(BeanUtils.toBean(pageResult, ErpBomRespVO.class));
    }

    private PageResult<ErpBomDTO> buildErpBomRespVoPageResult(PageResult<ErpBomDO> pageResult) {
        if (CollUtil.isEmpty(pageResult.getList())) {
            return PageResult.empty(pageResult.getTotal());
        }
        // 物料信息
        Map<Long, ErpMaterialInfoResp> materialMap = erpMaterialApi.getMaterialMap(
                convertSet(pageResult.getList(), ErpBomDO::getFmaterialid));
        // BOM组
        List<BomGroupStandardDO> bomGroupList = bomGroupStandardService.getBomGroupStandardListByIds(convertSet(pageResult.getList(), ErpBomDO::getFbomgroupid));
        Map<Long, BomGroupStandardDO> bomGroupStandardDOMap =
                convertMap(bomGroupList, BomGroupStandardDO::getId);
//        // BOM类型
//        List<DictDataDO> bomTypeList =
//                dictDataService.getDictDataList(CommonStatusEnum.ENABLE.getStatus(), ERP_BOM_BOM_TYPE);
//        Map<Integer, DictDataDO> bomTypeMap =  convertMap(bomTypeList, DictDataDO::getValueInteger);
//        // BOM用途
//        List<DictDataDO> bomUseList =
//                dictDataService.getDictDataList(CommonStatusEnum.ENABLE.getStatus(), ERP_BOM_BOM_PURPOSE);
//        Map<Integer, DictDataDO> bomUseMap =  convertMap(bomUseList, DictDataDO::getValueInteger);

        // 计量单位
        Map<Long, ErpMaterialUnitResp> unitRespVOMap = erpMaterialUnitApi.getMaterialUnitMap(
                convertSet(pageResult.getList(), ErpBomDO::getFunitid));

        PageResult<ErpBomDTO> result =  BeanUtils.toBean(pageResult, ErpBomDTO.class, erpBomRespVO ->{
            MapUtils.findAndThen(materialMap, erpBomRespVO.getFmaterialid(), erpProductRespVO -> erpBomRespVO.setFbarcode(erpProductRespVO.getBarCode()).setFmaterialname(erpProductRespVO.getName()));
            MapUtils.findAndThen(bomGroupStandardDOMap, erpBomRespVO.getFbomgroupid(), bomGroupStandardDO -> erpBomRespVO.setParentidBomGroup(bomGroupStandardDO.getParentid()).setFbomgroupname(bomGroupStandardDO.getName()));
//            MapUtils.findAndThen(bomUseMap, erpBomRespVO.getFusagetype(), dictDataDO -> erpBomRespVO.setFusagetypename(dictDataDO.getLabel()));
            MapUtils.findAndThen(unitRespVOMap, erpBomRespVO.getFunitid(), erpProductUnitDO -> erpBomRespVO.setFunitname(erpProductUnitDO.getName())); });
        return result;
    }

    @GetMapping("/export-excel")
    @Operation(summary = "导出bom Excel")
    @PreAuthorize("@ss.hasPermission('erp:bom:export')")
    @ApiAccessLog(operateType = EXPORT)
    public void exportBomExcel(@Valid ErpBomPageReqVO pageReqVO,
              HttpServletResponse response) throws IOException {
        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
        List<ErpBomDO> list = bomService.getBomPage(pageReqVO).getList();
        // 导出 Excel
        ExcelUtils.write(response, "bom.xls", "数据", ErpBomRespVO.class,
                        BeanUtils.toBean(list, ErpBomRespVO.class));
    }

    // ==================== 子表（bom分录） ====================

    @GetMapping("/bom-items/list-by-fparentid")
    @Operation(summary = "获得bom分录列表")
    @Parameter(name = "fparentid", description = "单据头")
    @PreAuthorize("@ss.hasPermission('erp:bom:query')")
    public CommonResult<List<ErpBomItemsRespVO>> getBomItemsListByFparentid(@RequestParam("fparentid") Long fparentid) {
        List<ErpBomItemsDO> result = bomService.getBomItemsListByFparentid(fparentid);
        return success(buildErpBomItemsRespVo(result));
//        return success(bomService.getBomItemsListByFparentid(fparentid));
    }
    @GetMapping("/bom-items/list-all-by-fparentid")
    @Operation(summary = "获得bom分录列表")
    @Parameter(name = "fparentid", description = "单据头")
    @PreAuthorize("@ss.hasPermission('erp:bom:query')")
    public CommonResult<List<ErpBomItemsRespVO>> getAllBomItemsListByFparentid(@RequestParam("fparentid") Long fparentid) {

        List<ErpBomItemsRespVO> finalResult = new ArrayList<>();

        List<ErpBomItemsRespVO> result = buildErpBomItemsRespVo(bomService.getBomItemsListByFparentid(fparentid));

        // 根据上述查询结果，每一项都要根据物料属性进行判断，如果是自制件，则需要以这个物料作为父级物料，继续查询物料的子物料
        for (ErpBomItemsRespVO item : result) {
            if (item.getFmaterialprop() == ErpMaterialAttrEnum.SELF_MADE_PARTS.getAttr()) { // 自制件
                item.setFseqShow(item.getFseq().toString());
                finalResult.add(item);
                // 查询该物料对应的BOM主表的信息
                ErpBomDO bom = bomService.getBomByMaterialId(item.getFmaterialid());
                if (bom != null) {
                    // 查询该物料的子物料
                    CommonResult<List<ErpBomItemsRespVO>> subCommonResult = getAllBomItemsListByFparentid(bom.getFid());
                    List<ErpBomItemsRespVO> subItems = subCommonResult != null ? subCommonResult.getData() : new ArrayList<>();
                    // 将子物料添加到结果列表中, 同时修改子物料的序号fseq为父级物料的序号fseq加上"-",再加上子物料的序号
                    for (int i = 0; i < subItems.size(); i++) {
                        ErpBomItemsRespVO subItem = subItems.get(i);
                        // 设置子物料的序号
                        subItem.setFseqShow(item.getFseqShow() + "-" + subItem.getFseqShow());
                    }
                    finalResult.addAll(subItems);
                }
            }else{
                item.setFseqShow(item.getFseq().toString());
                finalResult.add(item);
            }
        }
        return success(finalResult);
    }

    private List<ErpBomItemsRespVO> buildErpBomItemsRespVo(List<ErpBomItemsDO> result) {
        if (CollUtil.isEmpty(result)) {
            return Collections.emptyList();
        }
        // 物料信息
        Map<Long, ErpMaterialInfoResp> materialMap = erpMaterialApi.getMaterialMap(
                convertSet(result, ErpBomItemsDO::getFmaterialid));
        //单位信息
        Map<Long, ErpMaterialUnitResp> unitRespVOMap = erpMaterialUnitApi.getMaterialUnitMap(
                convertSet(result, ErpBomItemsDO::getFunitid));
        // 物料属性
        List<DictDataDO> materialAttrList =
                dictDataService.getDictDataList(CommonStatusEnum.ENABLE.getStatus(), DictTypeConstants.ERP_MATERIAL_ATTR);
        Map<Integer, DictDataDO> materialAttrMap =  convertMap(materialAttrList, DictDataDO::getValueInteger);
        // 基本状态
        List<DictDataDO> list =
                dictDataService.getDictDataList(CommonStatusEnum.ENABLE.getStatus(), DictTypeConstants.ERP_BILL_STATUS);
        Map<Integer, DictDataDO> billStatusrMap =  convertMap(list, DictDataDO::getValueInteger);
        // 领送料方式
//        List<DictDataDO> materialOutList =
//                dictDataService.getDictDataList(CommonStatusEnum.ENABLE.getStatus(), DictTypeConstants.ERP_MATERIAL_OUT);
//        Map<Integer, DictDataDO> materialOutMap =  convertMap(materialOutList, DictDataDO::getValueInteger);
        // 消耗类型
//        List<DictDataDO> consumeTypeList =
//                dictDataService.getDictDataList(CommonStatusEnum.ENABLE.getStatus(), DictTypeConstants.ERP_COST_TYPE);
//        Map<Integer, DictDataDO> consumeTypeMap =  convertMap(consumeTypeList, DictDataDO::getValueInteger);
        // 工序
        Map<Long, ErpProduceProcessDO> processMap =
                erpProduceProcessService.getProcessMap(
                        convertSet(result, ErpBomItemsDO::getFprocess));
//        Map<Integer, DictDataDO> processMap =  convertMap(processList, DictDataDO::getValueInteger);

        // 领料仓库
        Map<Long, KeyValue<String, Boolean>> warehouseMap = erpWarehouseApi.getWarehouseMap();



        List<ErpBomItemsRespVO> resultResp =  BeanUtils.toBean(result, ErpBomItemsRespVO.class, erpBomItemsRespVO ->{
            MapUtils.findAndThen(unitRespVOMap, erpBomItemsRespVO.getFunitid(), erpProductUnitDO -> erpBomItemsRespVO.setFunitname(erpProductUnitDO.getName()));
            MapUtils.findAndThen(materialMap, erpBomItemsRespVO.getFmaterialid(), product -> erpBomItemsRespVO.setFbarcode(product.getBarCode()).setFmaterialname(product.getName())
                    .setFmodel(product.getStandard()));
            MapUtils.findAndThen(materialAttrMap, erpBomItemsRespVO.getFmaterialprop(), materialAttr -> erpBomItemsRespVO.setFmaterialpropname(materialAttr.getLabel()));
            MapUtils.findAndThen(billStatusrMap, erpBomItemsRespVO.getFbasestatus(), billStatus -> erpBomItemsRespVO.setFbasestatusname(billStatus.getLabel()));
            MapUtils.findAndThen(processMap, erpBomItemsRespVO.getFprocess(), process -> erpBomItemsRespVO.setFprocessname(process.getProcessName()));
            MapUtils.findAndThen(warehouseMap, erpBomItemsRespVO.getFdefaultwarehouseid(), warehouse -> erpBomItemsRespVO.setFdefaultwarehousename(warehouse.getKey()));
        });
        return resultResp;
    }

}